package core;

import java.util.ArrayList;

import parsing.InvalidFunctionException;
import parsing.Parser;

//import com.sun.org.apache.xpath.internal.functions.Function;
import functions.Function;
import functions.FunctionIF;
public class NewtonRaphson extends Method {

	private double initialX;
	public NewtonRaphson(int numOfIteration, double precision , double initX) {
		super(numOfIteration, precision);
		initialX = initX;
	}

	@Override
	public ArrayList<Point> run(Function f) {
		function=f;
		FunctionIF diff = f.diff();
		ArrayList<Point> res = new ArrayList<Point>();
		double initialY = f.eval(initialX);
		if(Math.abs(initialY)>2)
		{
			initialX = estimateX(f);
			initialY = f.eval(initialX);
		}
		Point p = new Point(initialX,initialY);
		res.add(p);
		while(Math.abs(p.getY())>precision && res.size()<numOfIteration)
		{
			double newX=0;
			double diffValue = diff.eval(p.getX());
			if(diffValue == 0)
				System.out.println("Can't devide by zero");
			newX = p.getX() - (p.getY()/diffValue);
			p=new Point(newX ,f.eval(newX));
			res.add(p);
		}
		finalX = p.getX();
		return res;
	}

	private double estimateX(Function f) {
		if(Math.abs(f.eval(0))<1.5)return 0;
		for(int i=1;i<101;i++)
		{
			if(Math.abs(f.eval(i))<1.5)
				return i;
			if(Math.abs(f.eval(-1*i))<1.5)
				return i;
		}
		return 0;
	}

	@Override
	public double getErrorBound() {
		FunctionIF secDriv = function.diff().diff();
		double coeff = Math.pow(finalX-initialX,2)/2;
		double Bound1 = secDriv.eval(finalX);
		double Bound2 = secDriv.eval(initialX);
		return coeff*(Bound1>Bound2?Bound1:Bound2);
	}
	
public static void main(String[] args) throws InvalidFunctionException {
	Parser p = new Parser();
	Function f = p.parse("x^3 - 0.165*x^2 + 0.0003993");
	NewtonRaphson m = new NewtonRaphson(10, 0.00000000001, 5);
	ArrayList<Point> res = m.run(f);
	System.out.println(res.size());
	System.out.println(m.initialX);
	System.out.println(f.eval(m.finalX));
}
}
